package com.botarena.client.bot;

import java.util.HashMap;
import java.util.Map;

import com.botarena.client.ui.ErrorDialogBox;
import com.botarena.client.ui.InformationDialogBox;
import com.botarena.shared.ContestInfo;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;

public class BotNewFormWidget {

	private static final String DISCARD_BUTTON_LABEL = "Discard";
	private static final String SAVE_BUTTON_LABEL = "Save";

	private static final String MAIN_BUTTONS_WIDTH = "70px";

	private static final String NOT_EMPTY = "not empty!";

	private ContestInfo contestInfo;

	private TextBox name;
	private FileUpload source;
	private TextBox parameters;
	private CheckBox state;
	private TextBox contestKey;

	private Button discard;
	private Button save;

	private Map<String, String> errors;

	private VerticalPanel panel;
	private FormPanel form;
	private BotEditor botEditor;

	public BotNewFormWidget(BotEditor botEditor, ContestInfo contestInfo) {
		this.contestInfo = contestInfo;
		this.botEditor = botEditor;

		initWidgetElements();
		refresh();
	}

	private void resetErrors() {
		errors = new HashMap<String, String>();
		errors.put(name.getName(), "");
		errors.put(source.getName(), "");
		errors.put(parameters.getName(), "");
		errors.put(state.getName(), "");
	}

	public Panel getPanel() {
		return panel;
	}

	private void refresh() {

		form = new FormPanel();
		form.setAction("/botarena/createBot");

		form.setEncoding(FormPanel.ENCODING_MULTIPART);
		form.setMethod(FormPanel.METHOD_POST);

		FlexTable formTable = new FlexTable();
		formTable.setStyleName("formTable");

		formTable.setWidget(0, 0, new Label("Name:"));
		formTable.setWidget(1, 0, new Label("Source:"));
		formTable.setWidget(2, 0, new Label("Parameters:"));
		formTable.setWidget(3, 0, new Label("State:"));
		formTable.setWidget(4, 0, discard);

		formTable.setWidget(0, 1, name);
		formTable.setWidget(1, 1, source);
		formTable.setWidget(2, 1, parameters);
		formTable.setWidget(3, 1, state);
		formTable.setWidget(4, 1, save);
		formTable.setWidget(5, 1, contestKey);

		Label label = new Label(errors.get(name.getName()));
		label.setStyleName("errorLabel");
		formTable.setWidget(0, 2, label);

		label = new Label(errors.get(source.getName()));
		label.setStyleName("errorLabel");
		formTable.setWidget(1, 2, label);

		label = new Label(errors.get(parameters.getName()));
		label.setStyleName("errorLabel");
		formTable.setWidget(2, 2, label);

		label = new Label(errors.get(state.getName()));
		label.setStyleName("errorLabel");
		formTable.setWidget(3, 2, label);

		formTable.getCellFormatter().setHorizontalAlignment(4, 0,
				HasHorizontalAlignment.ALIGN_LEFT);
		formTable.getCellFormatter().setHorizontalAlignment(4, 1,
				HasHorizontalAlignment.ALIGN_RIGHT);

		addFormHandlers(new HTML());

		form.setWidget(formTable);
		panel.clear();
		panel.add(form);
	}

	private void initWidgetElements() {
		panel = new VerticalPanel();

		name = new TextBox();
		name.setName("name");
		source = new FileUpload();
		source.setName("uploadFormElement");
		parameters = new TextBox();
		parameters.setName("parameters");
		state = new CheckBox("contestant");
		state.setName("contestant");
		state.setValue(true);

		contestKey = new TextBox();
		contestKey.setName("contestKey");
		contestKey.setVisible(false);

		initDiscardButton();
		initSaveButton();
		resetErrors();
	}

	private void addFormHandlers(final HTML filePreview) {
		form.addSubmitHandler(new SubmitHandler() {

			public void onSubmit(SubmitEvent event) {
				if (!validateFields()) {
					event.cancel();
					refresh();
				}
			}
		});

		form.addSubmitCompleteHandler(new SubmitCompleteHandler() {

			public void onSubmitComplete(SubmitCompleteEvent event) {
				filePreview.setHTML(event.getResults());

				String result = event.getResults();
				if (result.contains("key: ")) {
					int keyIndex = result.indexOf("key: ") + 5;
					int index = result.indexOf("</pre>", keyIndex);

					String addedBotKey = (index == -1 ? 
							result.substring(keyIndex) : 
							result.substring(keyIndex, index));
					botEditor.addNewBot(addedBotKey);
					
					showInformationDialogBox("Success", "Bot successfully added");

					resetErrors();
					form.reset();
				} else {
					showErrorDialogBox("Error", result);
				}
			}
		});
	}

	private void initDiscardButton() {
		discard = new Button(DISCARD_BUTTON_LABEL, new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				form.reset();
			}
		});
		discard.setWidth(MAIN_BUTTONS_WIDTH);
	}

	private void initSaveButton() {
		save = new Button(SAVE_BUTTON_LABEL, new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				contestKey.setText(contestInfo.getKey());
				form.submit();
			}
		});
		save.setWidth(MAIN_BUTTONS_WIDTH);
	}

	protected boolean validateFields() {
		resetErrors();
		boolean valid = true;

		if (name.getText().equals("")) {
			errors.put(name.getName(), NOT_EMPTY);
			valid = false;
		}

		if (source.getFilename() == null || source.getFilename().length() == 0) {
			errors.put(source.getName(), NOT_EMPTY);
			valid = false;
		}

		return valid;
	}

	private void showInformationDialogBox(String title, String message) {
		InformationDialogBox dialog = new InformationDialogBox(title);
		dialog.setMessage(message);
		dialog.center();
	}
	
	private void showErrorDialogBox(String title, String message) {
		ErrorDialogBox dialog = new ErrorDialogBox(title);
		dialog.setMessage(message);
		dialog.center();
	}
}
